package com.example.security.config;

import com.example.base.config.AssemblyConfig;
import com.example.base.properties.LoginProperties;
import com.example.security.assembly.*;
import com.example.security.filter.JWTAuthenticationFilter;
import com.example.security.filter.PostLoginSecurityFilter;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@Slf4j
@Getter
@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Autowired
    private SystemUserDetailsService userDetailsService;

    @Autowired
    private JWTAuthenticationFilter jwtAuthenticationFilter;

    @Autowired
    private AssemblyConfig assemblyConfig;

    @Autowired
    private SysAuthenticatedAuthorizationManager manager;

    /**
     * 配置路径忽略 直接放行
     * 此处配置静态资源
     * @return
     */
    @Bean
    public WebSecurityCustomizer webSecurityCustomizer(){
        return (web) -> web.ignoring().antMatchers("/static/**");
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        String[] arr = assemblyConfig.getIgnoring().toArray(new String[0]);
        for (String path : arr){
            log.info("放行路径: {} ", path);
        }
        LoginProperties loginProperties = assemblyConfig.getLogin();
        /**
         * authenticated 配置用来检测是否已经登录 是统一配置
         * access 自定义对请求做判断 可以做是否登录 是否拥有权限
         */
        httpSecurity.authorizeHttpRequests(request -> {
            try {
                request.antMatchers(arr).permitAll()
                        .anyRequest().access(manager).and()
                        .formLogin()
                        //登录页面
                        .loginPage(loginProperties.getLoginPage())
                        .and()
                        //配置注销
                        .logout()
                        //注销登录请求地址
                        .logoutUrl(loginProperties.getLogoutUrl())
                        //注销登录处理
                        .addLogoutHandler(new SysLogoutHandler())
                        //登出成功后处理器
                        .logoutSuccessHandler(new SysLogoutSuccessHandler())
                        //注销成功后的跳转页面
                        .logoutSuccessUrl(loginProperties.getLogoutSuccessUrl())
                        .and()
                        //注册filter 用于验证token
                        .addFilterBefore(jwtAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                        //注册自定义的登录过滤器
                        .addFilterBefore(new PostLoginSecurityFilter(providerManager(), userDetailsService), UsernamePasswordAuthenticationFilter.class)
                        //关闭session
                        .sessionManagement().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                        //禁用csrf 因为不使用session
                        .and().csrf().disable();
            } catch (Exception e) {
                log.error("httpSecurity 配置异常", e);
            }
        });
        return httpSecurity.build();
    }

    @Bean
    public ProviderManager providerManager(){
        return new ProviderManager(new SystemAuthenticationProvider(userDetailsService));
    }
}
